#ifndef __KDTREE_SCENE_MANAGER_H__
#define __KDTREE_SCENE_MANAGER_H__

#include "OgreSceneManager.h"

namespace fmrt
{
	class KDTreeSceneManager : public Ogre::SceneManager
	{
	public: 
		KDTreeSceneManager(const Ogre::String& name); 
		~KDTreeSceneManager(); 
		
		virtual const String& getTypeName() const; 
		
		virtual void _findVisibleObjects(Ogre::Camera* cam, Ogre::VisibleObjectsBoundsInfo* visibleBounds, bool onlyShadowCasters); 
		
		/** Creates a RaySceneQuery for this scene manager. 
        @remarks
            This method creates a new instance of a query object for this scene manager, 
            looking for objects which fall along a ray. See SceneQuery and RaySceneQuery 
            for full details.
        @par
            The instance returned from this method must be destroyed by calling
            SceneManager::destroyQuery when it is no longer required.
        @param ray Details of the ray which describes the region for this query.
        @param mask The query mask to apply to this query; can be used to filter out
            certain objects; see SceneQuery for details.
        */
		virtual Ogre::RaySceneQuery* createRayQuery(const Ogre::Ray& ray, unsigned int mask = 0xFFFFFFFF); 
		
		/** Creates an IntersectionSceneQuery for this scene manager. 
        @remarks
            This method creates a new instance of a query object for locating
            intersecting objects. See SceneQuery and IntersectionSceneQuery
            for full details.
        @par
            The instance returned from this method must be destroyed by calling
            SceneManager::destroyQuery when it is no longer required.
        @param mask The query mask to apply to this query; can be used to filter out
            certain objects; see SceneQuery for details.
        */
		virtual Ogre::IntersectionSceneQuery* createIntersectionQuery(unsigned long mask = 0xFFFFFFFF); 
		
	protected: 
		
		virtual void clearScene(); 
		
		virtual bool fireRenderQueueEnded(uint8 id, const Ogre::String& invocation); 
		
		
		
	};
	

	/** KD-Tree specialization of IntersectionSceneQuery */
	class KDIntersectionSceneQuery : public Ogre::DefaultIntersectionSceneQuery
	{
	public:
		KDIntersectionSceneQuery(Ogre::SceneManager* creator);

		/** See IntersectionSceneQuery. */
		void execute(Ogre::IntersectionSceneQueryListener* listener);

	};
	
	/** KD-Tree specialization of RaySceneQuery */
	class KDRaySceneQuery : public Ogre::DefaultRaySceneQuery
    {
    public:
		KDRaySceneQuery(Ogre::SceneManager* creator);
        ~KDRaySceneQuery();

        /** See RaySceneQuery. */
		void execute(Ogre::RaySceneQueryListener* listener);
		
    protected:
        /// Set for eliminating duplicates since objects can be in > 1 node
		set<Ogre::MovableObject*>::type mObjsThisQuery;
        /// list of the last single intersection world fragments (derived)
		vector<Ogre::SceneQuery::WorldFragment*>::type mSingleIntersections;

        void clearTemporaries(void);
		
        /** Internal processing of a single node.
        @returns true if we should continue tracing, false otherwise
        */
        bool processNode(const KDTreeNode* node, const Ray& tracingRay, RaySceneQueryListener* listener,
            Real maxDistance = Math::POS_INFINITY, Real traceDistance = 0.0f);
	
        /** Internal processing of a single leaf.
        @returns true if we should continue tracing, false otherwise
        */
        bool processLeaf(const KDTreeNode* node, const Ray& tracingRay, RaySceneQueryListener* listener,
            Real maxDistance = Math::POS_INFINITY, Real traceDistance = 0.0f);

    };
	
	/** Factory method pattern
	*/ 
	class KDTreeSceneManagerFactory : public Ogre::SceneManagerFactory
	{
	public: 
		KDTreeSceneManagerFactory() {}
		~KDTreeSceneManagerFactory() {}
	
		static const Ogre::String FACTORY_TYPE_NAME; 
		SceneManager* createInstance(const String& instanceName);
		void destroyInstance(SceneManager* instance);
	};
}




#endif